/*  mudmap - A tool to create and organize user side maps for MUD games
 *  Copyright (C) 2012  Neop (aka moemneop, email: mneop@web.de)
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 *  for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, see <http://www.gnu.org/licenses/>.
 */

/*  File description
 *
 *  Classes that describe a world
 */

#pragma once

#include <utility>
#include <list>
#include <map>
#include <limits>

#include <glib-2.0/glib/gi18n.h>

#include "fileio.h"
#include "table.h"
#include "version.h"
#include "properties.h"

using std::map;

class layer;
class place;
class area;
class shop;
class teacher;

class color{
    public:
        color(int ri = 255, int gi = 255, int bi = 255){
            r = ri; g = gi; b = bi;
        }
        float get_flt_r(){
            return (float) r / 255;
        }
        float get_flt_g(){
            return (float) g / 255;
        }
        float get_flt_b(){
            return (float) b / 255;
        }
        bool operator!=(color rv){
            if(r != rv.r || g != rv.g || b != rv.b) return true;
            return false;
        }
        short r, g, b;
};

class layer : public table<place>{
    public:
        layer(int id){
            this->id = id;
            x_min = y_min = INT_MAX;
            x_max = y_max = INT_MIN;
        };
        int id;
        int x_min, x_max, y_min, y_max;
        void update_minmax(shared_ptr<place> pl);
};

class area{
    public:
        area(int id, string name){
            this->id = id;
            this->name = name;
            parent_place = -1;
        };
        int id;
        string name;
        int parent_place;
        color col;
};

class world;

class place{
    public:
        place(int id, string name, world *w);
        world *w;
        int id;
        string name;
        int area, layer;
        int posx, posy;
        int rec_lvl_min, rec_lvl_max, danger_lvl;
        map<string, int> ways;
        vector<int> children, parents;
        bool has_shop, has_teacher, has_free_food, has_free_beverages;

        /** Fügt eine Wegverbindung hinzu
        *  \param oexit Ausgang auf eigener Seite
        *  \param fexit Ausgang auf fremder Seite
        *  \param zu verbindender Ort
        */
        void add_way(string oexit, string fexit, shared_ptr<place> pl);
        void remove_way_to(int id);
        string get_exit_to_place(int plid);
        void remove_subarea(int plid);
        void remove_parent(int plid);
        /// true if exit is not a user-defined exit
        static bool get_exit_default(string exit);

        list<string> comments;
};

enum dir_t{
    DIR_NONE = 0,
    DIR_N,
    DIR_NE,
    DIR_E,
    DIR_SE,
    DIR_S,
    DIR_SW,
    DIR_W,
    DIR_NW,
    DIR_U,
    DIR_D,
    DIR_MANUAL
};

class world{
    public:
        /// Konstruktor, zum erstellen einer neuen Welt file = "" => keine Datei laden
        world(string file);
        virtual ~world();

        world *get_this(){
            return this;
        }

        string name;
        string file;
        color way_col, way_ndefault_col;
        int home_layer;
        float home_x, home_y;

        static bool static_initialized;
        static map<string, string> way_names;
        static map<string, dir_t> way_str_dir_t;
        static map<dir_t, string> way_dir_t_str;
        static map<string, string> way_str_mnemonic;

        shared_ptr<place> get_place(int id);
        shared_ptr<place> get_place(int x, int y, int lay);
        shared_ptr<layer> get_layer(int id);
        shared_ptr<area> get_area(int id);
        shared_ptr<shop> get_shop(int id);
        shared_ptr<teacher> get_teacher(int id);

        vector<pair<int, shared_ptr<area> > > get_area_vec();
        vector<pair<int, shared_ptr<area> > > get_area_vec_sorted();
        vector<pair<int, shared_ptr<place> > > get_place_vec();
        vector<pair<int, shared_ptr<place> > > get_place_vec_sorted();

        vector<int> get_danger_level_vec();
        color get_danger_level_col(int id);
        string get_danger_level_desc(int id);
        void set_danger_level(int id, string desc, color col);

        void add_way(shared_ptr<place> pl1, string exit1, shared_ptr<place> pl2, string exit2);
        void remove_way(shared_ptr<place> pl, string exit);
        shared_ptr<place> get_way(shared_ptr<place> pl, string exit);
        vector<pair<string, shared_ptr<place> > > get_ways(shared_ptr<place> pl);

        int get_new_layer_id();
        int get_new_place_id();
        int get_new_area_id();

        void add_place(shared_ptr<place> pl);
        void add_area(shared_ptr<area> ar);
        void add_shop(shared_ptr<shop> s);
        void add_teacher(shared_ptr<teacher> t);

        void remove_place(shared_ptr<place> pl);
        void move_place(shared_ptr<place> pl, int x, int y, int lay);

        void load();
        void save();
    private:
        map<int, shared_ptr<layer> > layers;
        map<int, shared_ptr<area> > areas;
        map<int, shared_ptr<place> > places;
        map<int, shared_ptr<shop> > shops;
        map<int, shared_ptr<teacher> > teachers;
        map<int, pair<color, string> > danger_lvl_col;
};
